from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token

from datetime import date

from .extend_model import *

import datetime


class Manageship(models.Model):
        cate = models.ForeignKey('Cate', on_delete=models.CASCADE, verbose_name='竞赛')
        department = models.ForeignKey('Department', on_delete=models.CASCADE, verbose_name='部门')
        note = models.CharField(max_length=50, blank=True, verbose_name='备注')


class Cate(models.Model):
        class Meta:
            verbose_name = '竞赛类目'
            verbose_name_plural = '竞赛类目列表'

        name = models.CharField(max_length=100, verbose_name='名称')
        nested_cate = models.ForeignKey('Cate', on_delete=models.CASCADE, related_name='parent_cate', blank=True, null=True, verbose_name='父竞赛类目')
        
        # 这里我们要动态更新
        layer = models.IntegerField()

        # 下面是业务相关的控制字段，未来可能会单独抽取出来
        NONE = 'none'
        NAME = 'name'
        LEVEL = 'level'
        SCORE = 'score'
        COMP_CATES = [
                (NONE, '未定义'),
                (NAME, '该竞赛以项目为成果'),
                (LEVEL, '该竞赛以等级为成果'),
                (SCORE, '该竞赛以成绩为成果')
        ]
        collect_part = models.CharField(max_length=5, choices=COMP_CATES, default=SCORE, verbose_name='收集指标')

        # 控制当前字段是否可以被收集
        collecable = models.BooleanField(default=True, verbose_name='是否可收集')


        def save(self, *args, **kwargs):
                self.layer = 0
                if self.nested_cate != None:
                        self.layer = self.nested_cate.layer + 1
                
                return super().save(*args, **kwargs)

        def __str__(self):
                return self.name


class Level(models.Model):
        name = models.CharField(max_length=10, verbose_name='名称')
        nested_level = models.ForeignKey('Level', on_delete=models.CASCADE, blank=True, null=True, verbose_name='父级别')
        cate = models.ForeignKey('Cate', on_delete=models.CASCADE, blank=True, null=True, verbose_name='竞赛')

        def __str__(self):
                # 我们要将其转换成完整的
                cur_level = self
                res_str = ''
                while cur_level:
                    res_str += ('-' if res_str else '' ) + cur_level.name
                    cur_level = cur_level.nested_level
                return res_str


# Is Here must needed?
class CollectCate(models.Model):
        class Meta:
            verbose_name = '证书收集'
            verbose_name_plural = '证书收集列表'

        cate = models.ForeignKey('Cate', on_delete=models.CASCADE, verbose_name='竞赛')
        
        # 增加开始时间和结束时间用于控制收集
        start_date = models.DateField(default=date.today, verbose_name='收集开始日期')
        # 默认开启5天收集时间
        end_date = models.DateField(default=datetime.date.today() + datetime.timedelta(days=5), verbose_name='收集结束日期')

        def __str__(self):
                return self.cate.name


class UserManager(BaseUserManager):
        def create_user(self, uid, password, name, department, telephone="", email="", commit=True):
                # If the department not exists, Is time to create ?
                user = self.model(
                        uid=uid,
                        name=name,
                        department=department,
                        telephone=telephone,
                        email=email
                )
                
                user.set_password(password)
                if commit:
                    user.save(using=self._db)
                return user

        def create_superuser(self, uid, password, name, department=None):
                # 管理员系统默认一个组 不能变
                if not Department.objects.filter(name='admin user group').exists():
                        Department.objects.create(name='admin user group').save()

                if department == None:
                        department = Department.objects.get(name='admin user group')
                user = self.create_user(uid, password, name, department, commit=False)
                user.is_staff = True
                user.save(using=self._db)
                return user


# We need define our own user model,
# Now we find that User Blong to department is also needed.
class User(AbstractBaseUser):
        class Meta:
            verbose_name = '用户'
            verbose_name_plural = '用户列表'

        uid = models.CharField(max_length=15, unique=True, verbose_name='学号（工号）') # Do not be pk!
        name = models.CharField(max_length=20, verbose_name='姓名')
        head = models.CharField(max_length=50, blank=True, verbose_name='头像')
        department = models.ForeignKey('Department', on_delete=models.CASCADE, verbose_name='部门')

        # Not must needed part
        telephone = models.CharField(max_length=11, blank=True, verbose_name='电话')
        email = models.EmailField(blank=True, verbose_name='电子邮箱')

        # Account manage
        is_active = models.BooleanField(default=True, verbose_name='是否激活可用')
        is_staff = models.BooleanField(default=False, verbose_name='是否为管理员')
        
        # Costum manager
        objects = UserManager()
        
        USERNAME_FIELD = 'uid'
        REQUIRED_FIELDS = ['name']

        def has_perm(self, perm, obj=None):
                return True

        def has_module_perms(self, app_label):
                return True

        def __str__(self):
                return f'{self.uid}-{self.name}'

class UserTag(models.Model):
    class Meta:
            verbose_name = '用户标签'
            verbose_name_plural = '用户标签列表'

    name = models.CharField(max_length=50, verbose_name='名称', unique=True)
    users = models.ManyToManyField(User)

    def __str__(self):
        return self.name

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
        if created:
                Token.objects.create(user=instance)

class Join(models.Model):
        class Meta:
            verbose_name = '审批关系'
            verbose_name_plural = '审批关系列表'

        cert = models.ForeignKey('Cert', on_delete=models.CASCADE, verbose_name='证书')
        user = models.ForeignKey('User', on_delete=models.CASCADE, verbose_name='用户')

        # 控制当前Join是参照哪个限制进来的
        restrict = models.ForeignKey('DepartRestrict', on_delete=models.CASCADE, verbose_name='限制')

        # 添加参与度支持 从100里面扣除
        play_role_imp = models.IntegerField(default=0, verbose_name='参与度')
        
        # 当前用户的批准状态
        ACCEPT = 'acc'
        REJECT = 'rej'
        UNKNOWN = 'unn'
        JOIN_STATUS = [
                (ACCEPT, '同意'),
                (REJECT, '拒绝'),
                (UNKNOWN, '未表态')
        ]
        status = models.CharField(max_length=3, choices=JOIN_STATUS, default=UNKNOWN, verbose_name='状态')
        msg = models.CharField(max_length=100, blank=True, null=True, verbose_name='反馈消息')

        acc_date = models.DateField(default=date.today, verbose_name='操作时间')

        def __str__(self):
            return self.user.name

class CertPic(models.Model):
        class Meta:
            verbose_name = '证书照片'
            verbose_name_plural = '证书照片列表'

        # 这里应当实现一个图片管理，先只做证书的
        cert = models.ForeignKey('Cert', on_delete=models.CASCADE, verbose_name='证书')
        name = models.CharField(max_length=50, verbose_name='文件名') # 这里需要根据实际情况设定

class Cert(models.Model):
        class Meta:
            verbose_name = '证书'
            verbose_name_plural = '证书列表'

        cate = models.ForeignKey('CollectCate', on_delete=models.CASCADE, verbose_name='竞赛')

        EXTRA_FIELDS = ('name', 'level', 'score')
        name = models.CharField(max_length=30, blank=True, verbose_name='竞赛名称')
        level = models.ForeignKey('Level', on_delete=models.CASCADE, blank=True, null=True, verbose_name='竞赛等级')
        score = models.CharField(max_length=5, blank=True, verbose_name='竞赛成绩')

        achieved_date = models.DateField(verbose_name='获奖时间')

        all_accept = models.BooleanField(default=False, verbose_name='全部通过')

        def __str__(self):
                return f'{self.cate}获奖证书'

        def get_comp_name(self):
            return self.cate.cate.name

        def get_comp_level(self):
            if self.cate.cate.nested_cate:
                return self.cate.cate.nested_cate.name
            return None

        def get_name(self):
            return self.name

        def get_user_list(self, type):
            return [join.user.name for join in self.join_set.filter(restrict__restrict_type=type).all()]

        def get_level(self):
            if self.level:
                return self.level
            return None

        def get_achieve_date(self):
            return self.achieved_date


class Department(models.Model):
        class Meta:
            verbose_name = '学院部门'
            verbose_name_plural = '学院部门列表'

        name = models.CharField(max_length=20, unique=True, verbose_name='名称')
        # 父部门
        nested_department = models.ForeignKey('Department', on_delete=models.CASCADE, blank=True, null=True, verbose_name='父部门')

        # admin 页面控制字段
        display = models.BooleanField(default=True, verbose_name='是否显示在父部门列表中')

        def __str__(self):
                de_list = []
                cur_dep = self
                while cur_dep != None:
                        de_list.append(cur_dep.name)
                        cur_dep = cur_dep.nested_department
                return '<'.join(de_list)        

# 在创建cate的时候应当完成创建，同时还要展示出来
class DepartRestrict(models.Model):
        class Meta:
            verbose_name = '部门限制'
            verbose_name_plural = '部门限制列表'

        # 用于标记允许添加的用户组
        cate = models.ForeignKey('Cate', on_delete=models.CASCADE, verbose_name='竞赛')
        department = models.ForeignKey('Department', on_delete=models.CASCADE, verbose_name='部门')

        # 如果这里添加控制 那么在添加证书的时候也应该指定限制，这样才能避免相同部门但是不知道谁是谁
        JOINER = 'joiner'
        ADVISOR = 'advisor'
        CHECKER = 'checker'
        RESTRICT_TYPES = [
            (JOINER, '参加竞赛'),
            (ADVISOR, '指导教师'),
            (CHECKER, '外部审批者')
        ]
        restrict_type = models.CharField(max_length=7, choices=RESTRICT_TYPES, verbose_name='参与竞赛类型')


        # 限制里面可以添加的人
        people_limit_min = models.IntegerField(default=1, verbose_name='最少人数限制')
        people_limit_max = models.IntegerField(default=1, verbose_name='最多人数限制')

        # 优先级，只有小的审批完毕才能审批大的
        priority = models.IntegerField(default=0, verbose_name='优先级')

        def __str__(self):
            return self.cate.name + '-' + self.department.name + '/' + str(self.priority)
